home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- Title: Simple harmonizer - a real-time audio pitch bender example program
-
- Program: harmonizer.c
-
- Author: Dan Fink
-
- Compile: cc harmonizer.c -o harmonizer -laudio -laudiofile -laudioutil -lm
-
- Usage: harmonizer note1 <note2 note3 ... >
-
- Output is to the standard Indigo audio device (speaker).
-
- Notes are specified by an integer relating
- the note in half steps to middle C.
-
- Middle C would be 0. C# would be 1
-
- for no effect at all : harmonizer 0
- for the chipmunk effect : harmonizer 12
- for a deep voice machine : harmonizer -7
- to simulate a major cord : harmonizer 0 4 7
-
- Comments:
-
- Advise running as root or suid root to take advantage of
- memory pinning and non-degrading high priority
- of audio process.
-
- Libraries you need to compile with come from the Digital
- Media Development option, now up to version 1.1 (for
- systems running IRIX 4.0.X) and version 1.2 (for systems
- running IRIX 5.1)
-
- Pitch shifting of realtime input from the microphone.
-
- Code isn't optimized.
-
- With the computing power of the indigo R3k, about 4 notes
- can be harmonized simultaneously without a problem.
- R4k does well up to even 8 notes.
-
- */
-
- #include <stdio.h>
- #include <limits.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/prctl.h>
- #include <sys/schedctl.h>
- #include <sys/prctl.h>
- #include <sys/lock.h>
- #include <signal.h>
- #include <audio.h>
- #include <audiofile.h>
- #include <math.h>
- #include <malloc.h>
-
-
- /* AUDIO DEFINES */
- #define BUFFERSIZE 1500 /* Size of output sample buffer. */
- #define PI 3.141592653 /* Our old friend from trig. */
- #define TWELFTH_ROOT_OF_2 1.0594631
- #define MAXKEYS 8
- #define MIDDLEC 72
-
-
- /* AUDIO ROUTINES */
- void audioinit();
- void audioloop(void *);
- void process_continuous_audio( short *, short *, long);
- void audioexit(int);
-
-
- /* AUDIO RELATED GLOBALS */
- ALport audioout;
- ALport audioin;
- ALconfig audioconfig;
- int audiodone = 0;
-
- /* OTHER GLOBALS */
- short key[MAXKEYS];
- int done = 0;
-
-
- void sigcat() /* for proper audio exit so a larger program's structure is
- easily divisible into master process and audio process */
- {
- done = 1;
- }
-
-
- /* AUDIO ROUTINES */
-
- void audioinit() /* Configure the audio port */
- {
- audioconfig = ALnewconfig(); /* Get a new audio configuration */
-
- /*
- ALsetsampfmt( audioconfig, AL_SAMPFMT_FLOAT);
- ALsetfloatmax(audioconfig, 1.0);
- */
- /* Floats will vary from -1.0 to 1.0*/
-
-
- ALsetqueuesize(audioconfig,BUFFERSIZE*2);
- /* Set the sample queue size to be twice that of our sound buffer */
-
- ALsetchannels(audioconfig,AL_MONO); /* Use mono */
-
- audioout = ALopenport("out","w",audioconfig);
- if (audioout == NULL) {
- printf("couldn't open audio port for output\n");
- audioexit(-1);
- }
-
- audioin = ALopenport("in","r",audioconfig); /* Open audio for writing */
- if (audioin == NULL) {
- printf("couldn't open audio port for input\n");
- audioexit(-1);
- }
- }
-
-
- void audioloop(void *foo) /* Audio process main loop */
- {
- short outbuf[BUFFERSIZE]; /* Sample buffer for computations */
- short inbuf[BUFFERSIZE]; /* Sample buffer for computations */
-
- if(schedctl(NDPRI,0,NDPHIMAX) == -1)
- printf("Couldn't run at high, non-degrading priority\n.");
- /* Make this process run at a high, non- */
- /* degrading priority. This help significantly */
- /* "smooth out" audio clicking caused by losing*/
- /* the CPU to other processes. Works best when*/
- /* the effective user id is the root user. */
-
- if(plock(PROCLOCK)!=0)
- printf("Couldn't lock process into memory\n.");
- /* Lock this process into memory - make it */
- /* immune to page swapping. Again, this is */
- /* another aid in preventing clicking which*/
- /* works when the effective user id is the */
- /* root user. */
-
- audioinit(); /* Initialize audio */
- while(!done) { /* Keep going until gfx process says otherwise */
-
- ALreadsamps(audioin,inbuf,BUFFERSIZE);
-
- process_continuous_audio(inbuf,outbuf,BUFFERSIZE);
-
- while(ALgetfillable(audioout) < BUFFERSIZE)
- sginap(1);
- /* Wait til theres enough room to write the entire */
- /* copy of our sound buffer to the audio queue. */
-
- ALwritesamps(audioout,outbuf,BUFFERSIZE);
- /* Output samples to audio port */
- }
-
- while(ALgetfilled(audioout) > 0);
- /* Wait till all the sound has been played before closing the port. */
-
- audioexit(0);
- }
-
-
- void process_continuous_audio(short *inbuf, short *outbuf, long buflen)
- {
- static float index[MAXKEYS];
- static int firsttime = 1;
-
- float maxkey = (float)MAXKEYS;
- float ratio;
- int i,j;
-
- /*
- Harmonizer algorithm :
-
- Assume that the original pitch that we're bending
- has its orginal pitch at MIDDLEC. This is
- an arbitrary starting point and could be anything.
-
- To halve the pitch (move it down an octave) we
- duplicate samples. AS expected, only half of the
- input buffer is used as it gets copied to the audio
- output buffer.
-
- To double the pitch (move it up an octave) we
- just copy every other sample of the original sound
- into the audio output buffer.
-
- Both of these are handled by computing the ratio
- of the original pitch to the desired output pitch.
- And skipping/repeating samples accordingly.
-
- For an octave higher, the ratio is 2.0:1.0 and
- samples are skipped. For an octave lower, the
- ration is 0.5:1.0 and samples are doubled.
- For a musical interval of a perfect fifth higher,
- the ration is 1.5:1.0, etc.
-
- To make calculations based on a piano keyboard, the
- TWELFTH_ROOT_OF_TWO is used as a multiplier to
- find any pitch on the piano keyboard. The number
- of half-steps away a pitch is from MIDDLEC is
- the power that the ratio is raised to. Thus,
- the C-sharp above MIDDLEC has a ratio of
- TWELFTH_ROOT_OF_TWO:1.0 with respect to MIDDLEC.
- The D Natural above MIDDLE C is
- TWELFTH_ROOT_OF_TWO ^ 2 : 1.0 with repect to
- MIDDLEC and so forth.
-
- The output pitch is based on the sampled audio input
- only. So this the time over which the pitch is
- harmonized is discetized and only the audio input
- buffer for that duration of time is used as the
- sample input for the algorithm. Consequently,
- a continuous version of this algorithm (ala
- glissando) would be less efficient to code.
-
-
- */
- if(firsttime)
- {
- for(j=0;j<MAXKEYS;j++)
- index[j]=0.0;
- firsttime = 0;
- }
-
- for(i=0; i<buflen; i++)
- outbuf[i] = 0;
-
- for(j=0;j<MAXKEYS;j++)
- {
- if(key[j]>0) /* For each key in that is on in the
- known state of the keyboard, perform
- the operations necessary for sound. */
- {
- ratio = powf(TWELFTH_ROOT_OF_2,
- (float)(key[j]-MIDDLEC));
-
- for(i=0; i<buflen; i++)
- {
- outbuf[i] += inbuf[(int)index[j]%buflen]/MAXKEYS;
- index[j] += ratio;
- }
- }
- }
- }
-
-
- void audioexit(int exitval) /* Gracefully exit the audio process */
- {
- if (audioconfig != NULL) ALfreeconfig(audioconfig);
- if (audioout != NULL) ALcloseport(audioout);
- if (audioin != NULL) ALcloseport(audioin);
-
- printf("audio closed down OK\n.");
- audiodone = 1;
- exit(exitval);
- }
-
-
- int main(int argc, char *argv[])
- {
- int whichkey;
- int arg;
- /* set up signal handler for correct temrination */
- signal(SIGINT,sigcat);
- signal(SIGTERM,sigcat);
-
- /* Initialize our concept of keyboard state */
- for(whichkey=0; whichkey<MAXKEYS; whichkey++)
- key[whichkey] = -1;
- whichkey = 0;
-
- if (argc == 1)
- {
- printf("usage: %s note <note2 note3 ...>\n",argv[0]);
- printf(" where each note is an integer between %d and %d\n",
- (-MIDDLEC),MIDDLEC);
- exit (-1);
- }
-
- printf("%d args \n",argc);
- for(arg = 1; arg<argc; arg++)
- if (whichkey < MAXKEYS)
- {
- printf("%d\n",MIDDLEC + atoi(argv[arg]));
- key[whichkey++] = (MIDDLEC + atoi(argv[arg]));
- }
-
- audioloop(&whichkey);
- }
-